as of May 2, 2018 all text in this notebook is just copy/pasted from the study2 notebook, so should largely be disregarded. will fill this in later
A few initial thoughts
Fundamentally, there are two major questions we want to ask/answer:
- How well can we predict the effect of the intervention on other beliefs using a previously-learned network (or by averaging over networks)?
- Given what we know about the intervention effect, what is the best model of the belief system?
The first is an out-of-sample prediction question, the second is more a model fit question. The first can be answered by generating predictions from hydenet, or possibly even by generating predictions with BRMS and using rejection sampling (since just conditioning on the assigned condition variable). The second can be addressed with either a cross validation and prediction scheme, or with WAIC via BRMS, either using imputed data or using a two-stage fitting process where posteriors from stage 1 are passed in as priors in stage 2.
In this notebook, I’m going to focus on the first issue: predicting effects of interventions from learned networks.
Predicting scale averages
Let’s see what the model predicts based on the change in the scale averages from pre-test to post-test. To transform this into something more like a real “fit”, one approach is to predict a distribution of change scores and then compare the predicted and observed distributions.
Disease Risk Condition
I’ll generate predictions for each of the 13 other nodes with diseaseSevere = pre-test mean and diseaseSevere = post-test mean, and see how those other nodes change. This is like imagining that all that’s changed between pre- and post-test is the information affecting diseaseSevere beliefs. So, conditioned only on what we know about how that changed, what should we expect would also change?
Once we start visualizing the error inherent in the data and estimates, only the prediction for “diseaseRare”, “overpar”, and “vaxtox” lie more than 1 standard error away from the observed mean. The all-important “vaxIntent” prediction is right about 1 SE away from the observed mean.
That’s part win for the model and part failure of the data to provide enough precision to really assess it strongly.
Below I do the actual inference with mcmc in jags, sampling from the multivariate distribution defined by the model graph.
NAs introduced by coercionattributes are not identical across measure variables;
they will be droppedJoining, by = "ResponseId"
Setting row names on a tibble is deprecated.The working directory was changed to /Users/derekpowell/Projects/Vaccines/Repos/vaccineBeliefs/study1 inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
Recall, here’s the network …
Predicted change scores against observed change scores (error bars = 95% CI) …
binding factor and character vector, coercing into character vectorbinding character and factor vector, coercing into character vector


bootstrapping CI
Here I’m going to bootstrap a confidence interval for the correlation between model predictions and observations for aggregated change scores across the 13 predicted scales.
I was thinking that it’s not quite right to do your standard “significance” test on this correlation, as these predicted/observed change scores aren’t values sampled from a population of variables. Instead, they represent their own population, but their measurement is uncertain, with that uncertainty coming from the participant-level data.
As I reflect on this I’m potentially a bit out of my depth, statistically. But the idea was I would take bootstrap samples of the data, make model predictions for each, then calculate the correlation with obtained values.
The results give a bit more confidence about the estimate than you’d have from the CI you’d get just treating the 13 points as a sample from a population (.303 to .914).
The mean correlation value is 0.748 and the bootstrapped 95% CI does not include zero. So, minimally, the model is picking up on something. Below is a histogram of correlation values, with a line marking the observed correlation in the original sample.
[1] 0.7477308
2.5% 97.5%
0.6259831 0.8553284

Modeling participant-wise predictions
We can also ask if the difference from pre to post-test for individual participants are similar to what we would expect according to the model. What I’m doing here is generating model predictions based on pretest diseaseSevere and posttest diseaseSevere ratings. Then, computing a predicted change score for each participant on each remaining scale, and adding that to their pretest scores to predict their posttest scores. I’m then truncating within the allowed range of -3 to 3, and recalculating a predicted change score.
So predicting posttest scores from pretest scores + predicted change scores, we do pretty well. The correlations overall seem good, but they are mostly driven by the knoweldge of the pretest scores.


That’s evidenced by the abysmal performance of the model to predict individual participants’ change scores. I am not quite sure how to explain them beyond the fact that the degree of predicted change is clearly dependent upon the prior score. That is, we expect smaller increases with high scores and smaller decreases with low scores, etc. In the case of scales where the model predictions are NEGATIVELY correlated, I think that might be the explanation. Right now the only thing in the model to guard against that is a simply truncation on the posttest predictions, bounding them within the range of -3 to 3. (but that doesn’t seem to affect the prediction/fit very much)

Average correlation between predicted and observed across all scales is approximately r = .1
So the model fails miserably at individual-level predictions, capturing changes only at the population level.
Baseline model (naïve bayes)
To evaluate the performance of our model, we should compare it to something else. I think a good baseline candidate is a “naïve bayes” or naïve causal model–where diseaseSevere predicts all other beliefs. This could be simulated by a series of linear regressions, but I think it will actually be easier to put it into hydenet.
Visually …
binding factor and character vector, coercing into character vectorbinding character and factor vector, coercing into character vector


And performance is essentially identical. That is, if we just naïvely assume disease severity drives all beliefs and we get just about as good a prediction as our more sophisticated model.

Though again, very poor individual-level predictions.
Of course, our learned structure accounts for the original correlational data far (infinitely?) better. As revealed by a \(\Delta AIC\) in the thousands.
[1] "naïve structure AIC = -244822"
[1] "learned structure AIC = -21115.34"
Preliminary conclusions
On some reflection, these results shoudln’t have been so shocking. Since the structure learning algorithm is working to find a graph that preserves the correlations among variables, it’s not so surprising that conditioning on disease severity in the graph produces roughly the same predictions as a set of regression models predicting all other node from disease severity (or equivalently, the “naïve” network I used here). However, the fact that those predictions map reasonably well onto what we observe is still important!
What’s better about the network structure models compared with naïve or univariate models?
- Fit both correlations between all scales and predict change scores on all scales
- Predict effects of educational interventions on any node or multiple nodes, all in one model
- Give ways to help diagnose which nodes were directly affected by interventions
- (Arguably) better allow interpretation of overall structure of belief system, better provide insights, etc
- Serve as a cognitive model of the belief system in important ways
If we have three models, one that lets us do prediction in one domain, another that lets us to do prediction in another domain, and one that does both – we should prefer the one that does both. Likewise, if we have three models, one that lets us do prediction, one that provides an intelligible cognitive theory, and one that does both–we should prefer the one that does both. So it would have been (or would be) a lot more exciting if the theory models could outperform the naïve models on both tasks, but it’s still interesting/cool if they do at least as well on multiple tasks as the other models each do on their one task.
That final point is important too. The (presumed) fact that the model will do better prediction treated as a cognitive model than as a causal model is very informative. In a sense, it’s actually supported by the naïve models too. A naïve model where disease severity predicts all beliefs is a very poor model of the overall system. But, it is a decent model of how the beliefs change. This would be very unlikely if what we were modeling was a simple causal system.
This also suggests a more general lesson: If beliefs are sufficiently interconnected and there are few v-structures, then the directions of each edge may matter very little in terms of prediction. Of course, this also means that setting those edge directions (if we care to do so), is going to be difficult. It might also mean it’s not the right way of concieving of the relationships among beliefs.
Going forward
In the next month or two, I think we should try to address a few questions before moving to publish …
- Can we use more sophisticated techniques to learn a better initial model that outperforms naïve models?
- Can we use this intervention data to learn a better model that will begin to outperform naïve models?
- How far can we push “naïve” models in terms of doing predictions?
LS0tCnRpdGxlOiAnVmFjY2luZXM6IE1hbnkgQmVsaWVmcyBTdHVkeSAzIC0gU2ltdWxhdGlvbnMnCmF1dGhvcjogIkthcmEgV2Vpc21hbiwgRGVyZWsgUG93ZWxsIgpkYXRlOiAiTWF5IDIsIDIwMTgiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IEZ9CmxpYnJhcnkodGlkeXZlcnNlKQoKYGBgCgpfX2FzIG9mIE1heSAyLCAyMDE4IGFsbCB0ZXh0IGluIHRoaXMgbm90ZWJvb2sgaXMganVzdCBjb3B5L3Bhc3RlZCBmcm9tIHRoZSBzdHVkeTIgbm90ZWJvb2ssIHNvIHNob3VsZCBsYXJnZWx5IGJlIGRpc3JlZ2FyZGVkLiB3aWxsIGZpbGwgdGhpcyBpbiBsYXRlcl9fCgojIEEgZmV3IGluaXRpYWwgdGhvdWdodHMKCkZ1bmRhbWVudGFsbHksIHRoZXJlIGFyZSB0d28gbWFqb3IgcXVlc3Rpb25zIHdlIHdhbnQgdG8gYXNrL2Fuc3dlcjoKCjEuIEhvdyB3ZWxsIGNhbiB3ZSBwcmVkaWN0IHRoZSBlZmZlY3Qgb2YgdGhlIGludGVydmVudGlvbiBvbiBvdGhlciBiZWxpZWZzIHVzaW5nIGEgcHJldmlvdXNseS1sZWFybmVkIG5ldHdvcmsgKG9yIGJ5IGF2ZXJhZ2luZyBvdmVyIG5ldHdvcmtzKT8KMi4gR2l2ZW4gd2hhdCB3ZSBrbm93IGFib3V0IHRoZSBpbnRlcnZlbnRpb24gZWZmZWN0LCB3aGF0IGlzIHRoZSBiZXN0IG1vZGVsIG9mIHRoZSBiZWxpZWYgc3lzdGVtPwoKVGhlIGZpcnN0IGlzIGFuIG91dC1vZi1zYW1wbGUgcHJlZGljdGlvbiBxdWVzdGlvbiwgdGhlIHNlY29uZCBpcyBtb3JlIGEgbW9kZWwgZml0IHF1ZXN0aW9uLiBUaGUgZmlyc3QgY2FuIGJlIGFuc3dlcmVkIGJ5IGdlbmVyYXRpbmcgcHJlZGljdGlvbnMgZnJvbSBoeWRlbmV0LCBvciBwb3NzaWJseSBldmVuIGJ5IGdlbmVyYXRpbmcgcHJlZGljdGlvbnMgd2l0aCBCUk1TIGFuZCB1c2luZyByZWplY3Rpb24gc2FtcGxpbmcgKHNpbmNlIGp1c3QgY29uZGl0aW9uaW5nIG9uIHRoZSBhc3NpZ25lZCBjb25kaXRpb24gdmFyaWFibGUpLiBUaGUgc2Vjb25kIGNhbiBiZSBhZGRyZXNzZWQgd2l0aCBlaXRoZXIgYSBjcm9zcyB2YWxpZGF0aW9uIGFuZCBwcmVkaWN0aW9uIHNjaGVtZSwgb3Igd2l0aCBXQUlDIHZpYSBCUk1TLCBlaXRoZXIgdXNpbmcgaW1wdXRlZCBkYXRhIG9yIHVzaW5nIGEgdHdvLXN0YWdlIGZpdHRpbmcgcHJvY2VzcyB3aGVyZSBwb3N0ZXJpb3JzIGZyb20gc3RhZ2UgMSBhcmUgcGFzc2VkIGluIGFzIHByaW9ycyBpbiBzdGFnZSAyLgoKSW4gdGhpcyBub3RlYm9vaywgSSdtIGdvaW5nIHRvIGZvY3VzIG9uIHRoZSBmaXJzdCBpc3N1ZTogcHJlZGljdGluZyBlZmZlY3RzIG9mIGludGVydmVudGlvbnMgZnJvbSBsZWFybmVkIG5ldHdvcmtzLgoKYGBge3IgdGlkeSwgaW5jbHVkZSA9IEZ9CiMgbG9hZCBkYXRhCmRfYWxsIDwtIHJlYWQuY3N2KCJkYXRhL3N0dWR5M19kYXRhLmNzdiIpCgojIHJlZm9ybWF0IHRvIG1hdGNoIHByZXZpb3VzIGFuYWx5c2VzIChpLmUuLCAyIHJvd3MgcGVyIHBhcnRpY2lwYW50KQpkX2RlbW8gPC0gZF9hbGwgJT4lIAogIHNlbGVjdCh3b3JrZXJJZCwgY29uZGl0aW9uLCBnZW5kZXIsIGFnZSwgZXRobmljaXR5LCBlZHVjYXRpb24sIGpvYiwgaW5jb21lLAogICAgICAgICBwb2xpdGljYWxfcGFydHksIHBvbGl0aWNhbF9iZWxpZWZzLCBlbGlnaWJsZV9wcmV0ZXN0LCAKICAgICAgICAgaXNfcGFyZW50X3Bvc3R0ZXN0LCBjaGlsZHJlbl9udW1fcG9zdHRlc3QsIGNoaWxkcmVuX29sZGVzdF9wb3N0dGVzdCwgCiAgICAgICAgIGNoaWxkcmVuX3lvdW5nZXN0X3Bvc3R0ZXN0LCBwbGFuX3BhcmVudF9wb3N0dGVzdCwKICAgICAgICAgc3RhcnRzX3dpdGgoImZsdXNob3RfIiksIHN0YXJ0c193aXRoKCJ2YXhfIiksIHN0YXJ0c193aXRoKCJhdHRlbnRpb25fIiksCiAgICAgICAgIHN0YXJ0c193aXRoKCJjb21tZW50cyIpLCBzdGFydHNfd2l0aCgiZHVyYXRpb24iKSkKZF9wcmUgPC0gZF9hbGwgJT4lIAogIHNlbGVjdCh3b3JrZXJJZCwgZW5kc193aXRoKCJfcHJldGVzdCIpKSAlPiUKICBzZWxlY3QoLWMoZWxpZ2libGVfcHJldGVzdCwgc3RhcnRzX3dpdGgoImZsdXNob3RfIiksIHN0YXJ0c193aXRoKCJ2YXhfIiksIAogICAgICAgICAgICBzdGFydHNfd2l0aCgiYXR0ZW50aW9uXyIpLCBzdGFydHNfd2l0aCgiY29tbWVudHMiKSwgCiAgICAgICAgICAgIHN0YXJ0c193aXRoKCJkdXJhdGlvbiIpKSkgJT4lCiAgcmVuYW1lX2FsbChmdW5zKGdzdWIoIl9wcmV0ZXN0IiwgIiIsIC4pKSkgJT4lCiAgbXV0YXRlKHBoYXNlID0gInByZSIpCmRfcG9zdCA8LSBkX2FsbCAlPiUgCiAgc2VsZWN0KHdvcmtlcklkLCBlbmRzX3dpdGgoIl9wb3N0dGVzdCIpKSAlPiUKICBzZWxlY3QoLWMoaXNfcGFyZW50X3Bvc3R0ZXN0LCBjaGlsZHJlbl9udW1fcG9zdHRlc3QsIGNoaWxkcmVuX29sZGVzdF9wb3N0dGVzdCwKICAgICAgICAgICAgY2hpbGRyZW5feW91bmdlc3RfcG9zdHRlc3QsIHBsYW5fcGFyZW50X3Bvc3R0ZXN0LAogICAgICAgICAgICBzdGFydHNfd2l0aCgiZmx1c2hvdF8iKSwgc3RhcnRzX3dpdGgoInZheF8iKSwgc3RhcnRzX3dpdGgoImF0dGVudGlvbl8iKSwKICAgICAgICAgICAgc3RhcnRzX3dpdGgoImNvbW1lbnRzIiksIHN0YXJ0c193aXRoKCJkdXJhdGlvbiIpKSkgJT4lCiAgcmVuYW1lX2FsbChmdW5zKGdzdWIoIl9wb3N0dGVzdCIsICIiLCAuKSkpICU+JQogIG11dGF0ZShwaGFzZSA9ICJwb3N0IikKCmQgPC0gYmluZF9yb3dzKGRfcHJlLCBkX3Bvc3QpICU+JSAKICBnYXRoZXIocXVlc3Rpb24sIHJlc3BvbnNlLCAtYyh3b3JrZXJJZCwgcGhhc2UpKSAlPiUKICBtdXRhdGUocGhhc2UgPSBmYWN0b3IocGhhc2UsCiAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoInByZSIsICJwb3N0IikpLAogICAgICAgICByZXZlcnNlX2NhdCA9IGlmZWxzZShncmVwbCgiX1sxLTldciQiLCBxdWVzdGlvbiksIFRSVUUsIEZBTFNFKSwKICAgICAgICAgIyBOT1RFOiAicmVzcG9uc2UiIGhhcyBhbHJlYWR5IGJlZW4gcmV2ZXJzZSBjb2RlZCEKICAgICAgICAgcXVlc3Rpb24gPSBmYWN0b3IocXVlc3Rpb24pLAogICAgICAgICBzY2FsZSA9IGZhY3Rvcihnc3ViKCJfLiokIiwgIiIsIHF1ZXN0aW9uKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygidmFjY0ludGVudCIsICJ2YWNjRGFuZ2VyIiwgInZhY2NFZmYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidmFjY1N0cmFpbiIsICJ2YWNjVG94IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImRpc2Vhc2VTZXZlcmUiLCAiZGlzZWFzZVJhcmUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaW5mYW50SW1tTGltQ2FwIiwgImluZmFudEltbVdlYWsiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibWVkU2tlcHQiLCAiaGIiLCAibmF0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIm92ZXJwYXIiLCAicGFyZW50RXhwZXJ0IikpKSAlPiUKICBmdWxsX2pvaW4oZF9kZW1vKSAlPiUKICBtdXRhdGUoY29uZGl0aW9uID0gZmFjdG9yKGNvbmRpdGlvbiwgbGV2ZWxzID0gYygibm9JbnRlcnYiLCAiZGlzZWFzZVJpc2siKSkpICU+JQogIGZpbHRlcighaXMubmEocmVzcG9uc2UpLCAhaXMubmEod29ya2VySWQpLCAhaXMubmEoY29uZGl0aW9uKSkgJT4lCiAgZGlzdGluY3QoKQoKIyBob3cgbWFueSBsZWZ0PwpkICU+JSBkaXN0aW5jdCh3b3JrZXJJZCwgY29uZGl0aW9uKSAlPiUgY291bnQoY29uZGl0aW9uKQpgYGAKCmBgYHtyIHNjb3JlcywgaW5jbHVkZSA9IEZ9CiMgc2NvcmUgYWxsIHNjYWxlcwpkX3Njb3JlZCA8LSBkICU+JQogIHNlbGVjdCh3b3JrZXJJZCwgY29uZGl0aW9uLCBwaGFzZSwgc2NhbGUsIHJlc3BvbnNlLAogICAgICAgICBnZW5kZXI6ZHVyYXRpb25fcG9zdHRlc3QpICU+JQogIGdyb3VwX2J5KHdvcmtlcklkLCBjb25kaXRpb24sIHBoYXNlLCBzY2FsZSkgJT4lCiAgbXV0YXRlKHJlc3BvbnNlID0gYXMubnVtZXJpYyhyZXNwb25zZSkpICU+JQogIHN1bW1hcmlzZShNZWFuID0gbWVhbihyZXNwb25zZSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGRpc3RpbmN0KCkKYGBgCgoKIyBQcmVkaWN0aW5nIHNjYWxlIGF2ZXJhZ2VzCgpMZXQncyBzZWUgd2hhdCB0aGUgbW9kZWwgcHJlZGljdHMgYmFzZWQgb24gdGhlIGNoYW5nZSBpbiB0aGUgc2NhbGUgYXZlcmFnZXMgZnJvbSBwcmUtdGVzdCB0byBwb3N0LXRlc3QuIFRvIHRyYW5zZm9ybSB0aGlzIGludG8gc29tZXRoaW5nIG1vcmUgbGlrZSBhIHJlYWwgImZpdCIsIG9uZSBhcHByb2FjaCBpcyB0byBwcmVkaWN0IGEgZGlzdHJpYnV0aW9uIG9mIGNoYW5nZSBzY29yZXMgYW5kIHRoZW4gY29tcGFyZSB0aGUgcHJlZGljdGVkIGFuZCBvYnNlcnZlZCBkaXN0cmlidXRpb25zLgoKIyMjIERpc2Vhc2UgUmlzayBDb25kaXRpb24KCkknbGwgZ2VuZXJhdGUgcHJlZGljdGlvbnMgZm9yIGVhY2ggb2YgdGhlIDEzIG90aGVyIG5vZGVzIHdpdGggX2Rpc2Vhc2VTZXZlcmVfID0gcHJlLXRlc3QgbWVhbiBhbmQgX2Rpc2Vhc2VTZXZlcmVfID0gcG9zdC10ZXN0IG1lYW4sIGFuZCBzZWUgaG93IHRob3NlIG90aGVyIG5vZGVzIGNoYW5nZS4gVGhpcyBpcyBsaWtlIGltYWdpbmluZyB0aGF0IGFsbCB0aGF0J3MgY2hhbmdlZCBiZXR3ZWVuIHByZS0gYW5kIHBvc3QtdGVzdCBpcyB0aGUgaW5mb3JtYXRpb24gYWZmZWN0aW5nIGRpc2Vhc2VTZXZlcmUgYmVsaWVmcy4gU28sIGNvbmRpdGlvbmVkIG9ubHkgb24gd2hhdCB3ZSBrbm93IGFib3V0IGhvdyB0aGF0IGNoYW5nZWQsIHdoYXQgc2hvdWxkIHdlIGV4cGVjdCB3b3VsZCBhbHNvIGNoYW5nZT8KCmBgYHtyfQoKc3VtbWFyaXplIDwtIHN1bW1hcmlzZQpkaXNlYXNlU2V2ZXJlTWVhbjAgPC0gZF9zY29yZWQgJT4lIAogIGZpbHRlcihjb25kaXRpb249PSJkaXNlYXNlUmlzayIsIHNjYWxlPT0iZGlzZWFzZVNldmVyZSIsIHBoYXNlPT0icHJlIikgJT4lIAogIHN1bW1hcml6ZShtZWFuID0gbWVhbihNZWFuKSkgJT4lCiAgYXMubnVtZXJpYygpCgpkaXNlYXNlU2V2ZXJlTWVhbjEgPC0gZF9zY29yZWQgJT4lIAogIGZpbHRlcihjb25kaXRpb249PSJkaXNlYXNlUmlzayIsIHNjYWxlPT0iZGlzZWFzZVNldmVyZSIsIHBoYXNlPT0icG9zdCIpICU+JSAKICBzdW1tYXJpemUobWVhbiA9IG1lYW4oTWVhbikpICU+JQogIGFzLm51bWVyaWMoKQoKYGBgCgoKT25jZSB3ZSBzdGFydCB2aXN1YWxpemluZyB0aGUgZXJyb3IgaW5oZXJlbnQgaW4gdGhlIGRhdGEgYW5kIGVzdGltYXRlcywgb25seSB0aGUgcHJlZGljdGlvbiBmb3IgImRpc2Vhc2VSYXJlIiwgIm92ZXJwYXIiLCBhbmQgInZheHRveCIgbGllIG1vcmUgdGhhbiAxIHN0YW5kYXJkIGVycm9yIGF3YXkgZnJvbSB0aGUgb2JzZXJ2ZWQgbWVhbi4gVGhlIGFsbC1pbXBvcnRhbnQgInZheEludGVudCIgcHJlZGljdGlvbiBpcyByaWdodCBhYm91dCAxIFNFIGF3YXkgZnJvbSB0aGUgb2JzZXJ2ZWQgbWVhbi4KClRoYXQncyBwYXJ0IHdpbiBmb3IgdGhlIG1vZGVsIGFuZCBwYXJ0IGZhaWx1cmUgb2YgdGhlIGRhdGEgdG8gcHJvdmlkZSBlbm91Z2ggcHJlY2lzaW9uIHRvIHJlYWxseSBhc3Nlc3MgaXQgc3Ryb25nbHkuCgoKQmVsb3cgSSBkbyB0aGUgYWN0dWFsIGluZmVyZW5jZSB3aXRoIG1jbWMgaW4gamFncywgc2FtcGxpbmcgZnJvbSB0aGUgbXVsdGl2YXJpYXRlIGRpc3RyaWJ1dGlvbiBkZWZpbmVkIGJ5IHRoZSBtb2RlbCBncmFwaC4KCmBgYHtyfQpzZXQuc2VlZCgxMjMpCmxpYnJhcnkoSHlkZU5ldCkKbGlicmFyeShyamFncykKbGlicmFyeShibmxlYXJuKQoKIyBsb2FkIGluIG1vZGVsIGZyb20gY29nc2NpIHBhcGVyCiMgbmV0LmZpdCA8LSByZWFkUkRTKCJuZXQtZml0LWNvZ3NjaTIwMTgucmRzIikKbmV0LnN0cnVjdCA8LSByZWFkUkRTKCJuZXQtc3RydWN0LWNvZ3NjaTIwMTgucmRzIikKCiMgbG9hZCBpbiBkYXRhIGZyb20gY29nc2NpIHBhcGVyCnNvdXJjZSgiLi4vc3R1ZHkxL3ZhY2NfaW1wb3J0X2RhdGEuUiIpCnNvdXJjZSgiLi4vU2NyaXB0cy9nbW9kX3Rvb2xzLlIiKQojIGdldCBtb2RlbCBvdXQgb2YgSFlERSBuZXR3b3JrCgojICMgSEVSRSBXRSBDQU4gVEVTVCBESUZGRVJFTlQgTU9ERUxTISBUSElTIElTIEEgUVVJQ0sgSEFDSyBKVVNUIFRPIFNFRSBJRiBUSElOR1MgQVJFIFNJTUlMQVIKIyBuZXQuc3RydWN0IDwtIG1taGMoZF9ibikKCm15X2h5ZGVfbmV0d29yayA8LSBibmxlYXJuX3RvX2h5ZGUobmV0LnN0cnVjdCkKbXlfaHlkZV9uZXR3b3JrIDwtIEh5ZGVOZXR3b3JrKGFzLmZvcm11bGEobXlfaHlkZV9uZXR3b3JrKSwgZGF0YT1hcy5kYXRhLmZyYW1lKGRfYm4pKQoKamFnc19tb2RlbCA8LSB3cml0ZU5ldHdvcmtNb2RlbChteV9oeWRlX25ldHdvcmspCgpkb19qYWdzX2luZmVyZW5jZSA8LSBmdW5jdGlvbihtb2RlbCwgdmFyaWFibGUubmFtZXMsIGRhdGEgPSBOVUxMLCBpdGVyID0gMWU0LCBzaWxlbnQ9VFJVRSkgewogIGlmIChzaWxlbnQpIHsKICAgIHBiYXIgPC0gIm5vbmUiCiAgfSBlbHNlIHsKICAgIHBiYXIgPC0gInRleHQiCiAgfQogIAogIGphZ3MgPC0gamFncy5tb2RlbCh0ZXh0Q29ubmVjdGlvbihtb2RlbCksIGRhdGEgPSBkYXRhLCBxdWlldD1zaWxlbnQpCiAgbW9kZWxfc2FtcGxlcyA8LSBjb2RhLnNhbXBsZXMoamFncywgdmFyaWFibGUubmFtZXMsIGl0ZXIqMiwgcHJvZ3Jlc3MuYmFyPSJub25lIikKICByZXR1cm4obW9kZWxfc2FtcGxlcykKfQoKbWFrZV9wcmVkaWN0aW9ucyA8LSBmdW5jdGlvbihtb2RlbCwgb3JpZ19kYXRhLCBub2Rlc190b19wcmVkaWN0LCBub2Rlc19oZWxkX291dD1jKCksIGl0ZXI9MWU0KSB7CiAgIyB0YWtlcyBhIG1vZGVsIGFuZCBkYXRhZnJhbWUgYW5kIGdlbmVyYXRlcyBtb2RlbCBwcmVkaWN0aW9ucyBmb3IgdmFyaWFibGVzIGxpc3RlZCBpbiAKICAjIG5vZGVzX3RvX3ByZWRpY3QuIEJ5IGRlZmF1bHQsIHVzZXMgYWxsIHJlbWFpbmluZyBub2RlcyBpbiBvcmlnX2RhdGEuIEhvbGQgb3V0IG5vZGVzIGZyb20KICAjIHByZWRpY3Rpb24gd2l0aCBub2Rlc19oZWxkX291dC4gaXRlciBzZXRzIG1jbWMgc2FtcGxlcwogIAogIHByZWRfZGYgPC0gb3JpZ19kYXRhCiAgcHJlZF9kZlssbm9kZXNfdG9fcHJlZGljdF0gPC0gTkEKICAKICBmb3IgKGkgaW4gMTpucm93KHByZWRfZGYpKSB7CiAgICByb3cgPC0gcHJlZF9kZltpLF0KICAgIHJvd1tub2Rlc19oZWxkX291dF0gPC0gTkEKICAgIHByZWQgPC0gZG9famFnc19pbmZlcmVuY2UobW9kZWwsIG5vZGVzX3RvX3ByZWRpY3QsIGRhdGEgPSByb3csIGl0ZXIgPSBpdGVyKQogICAgcG9pbnRfcHJlZHMgPC0gcm93TWVhbnModChwcmVkW1sxXV1bKGl0ZXIvMisxKTppdGVyLG5vZGVzX3RvX3ByZWRpY3RdKSkKICAgIHByZWRfZGZbaSxub2Rlc190b19wcmVkaWN0XSA8LSBwb2ludF9wcmVkcwogIH0KCiAgcmV0dXJuKHByZWRfZGYpCn0KCngxIDwtIGFzLmRhdGEuZnJhbWUodChjb2xNZWFucyhkX2JuKSkpCngyIDwtIGFzLmRhdGEuZnJhbWUodChjb2xNZWFucyhkX2JuKSkpCgoKeDFbLCJkaXNlYXNlU2V2ZXJlIl0gPC0gZGlzZWFzZVNldmVyZU1lYW4wCngyWywiZGlzZWFzZVNldmVyZSJdIDwtIGRpc2Vhc2VTZXZlcmVNZWFuMQoKdmFycyA8LSBkX3Njb3JlZCAlPiUgc2VsZWN0KHNjYWxlKSAlPiUgZmlsdGVyKHNjYWxlIT0iZGlzZWFzZVNldmVyZSIpICU+JSBkaXN0aW5jdCgpCnByZWQwIDwtIG1ha2VfcHJlZGljdGlvbnMoamFnc19tb2RlbCwgeDEsIGFzLmNoYXJhY3Rlcih2YXJzJHNjYWxlKSxpdGVyPTFlNSkKcHJlZDEgPC0gbWFrZV9wcmVkaWN0aW9ucyhqYWdzX21vZGVsLCB4MiwgYXMuY2hhcmFjdGVyKHZhcnMkc2NhbGUpLGl0ZXI9MWU1KQoKcHJlZDAgPC0gcHJlZDAgJT4lIGFzX3RpYmJsZSgpICU+JSBnYXRoZXIoc2NhbGUsIHZhbHVlKSAlPiUgbXV0YXRlKHBoYXNlID0gInByZSIpCnByZWQxIDwtIHByZWQxICU+JSBhc190aWJibGUoKSAlPiUgZ2F0aGVyKHNjYWxlLCB2YWx1ZSkgJT4lIG11dGF0ZShwaGFzZSA9ICJwb3N0IikKCnByZWRpY3Rpb25zIDwtIHByZWQwICU+JSAKICBiaW5kX3Jvd3MocHJlZDEpIAoKYGBgCgpSZWNhbGwsIGhlcmUncyB0aGUgbmV0d29yayAuLi4KCmBgYHtyfQpwbG90KG15X2h5ZGVfbmV0d29yaykKYGBgCgpQcmVkaWN0ZWQgY2hhbmdlIHNjb3JlcyBhZ2FpbnN0IG9ic2VydmVkIGNoYW5nZSBzY29yZXMgKGVycm9yIGJhcnMgPSA5NSUgQ0kpIC4uLgoKYGBge3J9CiMgbWFrZSBjaGFuZ2Ugc2NvcmUgZGYgd2l0aCBlcnJvciBpbmZvCiMgc3RhbmRhcmQgZXJyb3IgZnVuY3Rpb24Kc3RkZXJyIDwtIGZ1bmN0aW9uKHgpIHsKICAgICAgICAgIHNxcnQodmFyKHhbIWlzLm5hKHgpXSkgLyBsZW5ndGgoeFshaXMubmEoeCldKSkKfQoKCm9ic01lYW5zIDwtIGRfc2NvcmVkICU+JSAKICBmaWx0ZXIoY29uZGl0aW9uID09ICJkaXNlYXNlUmlzayIpICU+JSAKICBzcHJlYWQocGhhc2UsIE1lYW4pICU+JQogIG11dGF0ZShzY29yZSA9IHBvc3QgLSBwcmUpICU+JQogIGdyb3VwX2J5KHNjYWxlKSAlPiUKICBzdW1tYXJpemUoY2hhbmdlX3Njb3JlID0gbWVhbihzY29yZSksCiAgICAgICAgICAgIHN0ZF9lcnJvciA9IHN0ZGVycihzY29yZSkpICU+JQogIGZpbHRlcihzY2FsZSE9ImRpc2Vhc2VTZXZlcmUiKSAlPiUKICBtdXRhdGUodHlwZT0ib2JzZXJ2ZWQiKQoKIyAlPiUgCiMgICBzdW1tYXJpemUobWVhbl9yZXNwID0gbWVhbihNZWFuKSwKIyAgICAgICAgICAgICBzdGRfZXJyb3IgPSBzdGRlcnIoTWVhbikpICU+JSAKCnByZWRNZWFucyA8LSBwcmVkaWN0aW9ucyAlPiUgCiAgZ3JvdXBfYnkoc2NhbGUscGhhc2UpICU+JSAKICBzdW1tYXJpemUobWVhbl9yZXNwID0gbWVhbih2YWx1ZSkpICU+JQogIG11dGF0ZSh0eXBlPSJwcmVkaWN0ZWQiKSAlPiUKICBzcHJlYWQocGhhc2UsIG1lYW5fcmVzcCkgJT4lCiAgIyBncm91cF9ieShzY2FsZSkgJT4lCiAgbXV0YXRlKGNoYW5nZV9zY29yZSA9IHBvc3QgLSBwcmUsCiAgICAgICAgICAgIHN0ZF9lcnJvciA9IDApCgpkX3NpbSA8LSBvYnNNZWFucyAlPiUgYmluZF9yb3dzKHByZWRNZWFucykKCmRfc2ltICU+JQogIG11dGF0ZSgKICAgICAgICAgVUwgPSBjaGFuZ2Vfc2NvcmUgKyBzdGRfZXJyb3IqMS45NiwKICAgICAgICAgTEwgPSBjaGFuZ2Vfc2NvcmUgLSBzdGRfZXJyb3IqMS45NgogICAgICAgICApICU+JQogIGdncGxvdChhZXMoeSA9IHJlb3JkZXIoc2NhbGUsIGNoYW5nZV9zY29yZSksCiAgICAgICAgICAgICB4ID0gY2hhbmdlX3Njb3JlLAogICAgICAgICAgICAgeG1heCA9IFVMLCAKICAgICAgICAgICAgIHhtaW4gPSBMTCwgCiAgICAgICAgICAgICBjb2xvciA9IHR5cGUpKSArCiAgZ2VvbV9wb2ludChzaGFwZT0xNywgc2l6ZT0zKSArCiAgZ2VvbV9lcnJvcmJhcmgoaGVpZ2h0PTApICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKQpgYGAKCmBgYHtyfQpzaW1NZWFuIDwtIGRfc2ltICU+JSAKICBzZWxlY3QoLXBvc3QsLXByZSwgLXN0ZF9lcnJvcikgJT4lCiAgZmlsdGVyKHNjYWxlIT0iZGlzZWFzZVNldmVyZSIpICU+JQogIGdyb3VwX2J5KHR5cGUsc2NhbGUpICU+JQogIHNwcmVhZCh0eXBlLCBjaGFuZ2Vfc2NvcmUpCgoKc2ltTWVhbkNvciA8LSBjb3Ioc2ltTWVhbiRwcmVkaWN0ZWQsIHNpbU1lYW4kb2JzZXJ2ZWQpICU+JSByb3VuZCgzKQoKc2ltTWVhbiAlPiUKICBnZ3Bsb3QoYWVzKHg9cHJlZGljdGVkLCB5PW9ic2VydmVkKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV90ZXh0KGFlcyh4PS0uMSwgeT0gLjIsIGxhYmVsPXBhc3RlKCJyID0iLHNpbU1lYW5Db3IpKSkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArCiAgbGFicyh0aXRsZT0iQXZlcmFnZSBkaWZmZXJlbmNlIHNjb3JlcyIpICsKICB0aGVtZShhc3BlY3QucmF0aW8gPSAxKQpgYGAKCiMgYm9vdHN0cmFwcGluZyBDSQoKSGVyZSBJJ20gZ29pbmcgdG8gYm9vdHN0cmFwIGEgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gbW9kZWwgcHJlZGljdGlvbnMgYW5kIG9ic2VydmF0aW9ucyBmb3IgYWdncmVnYXRlZCBjaGFuZ2Ugc2NvcmVzIGFjcm9zcyB0aGUgMTMgcHJlZGljdGVkIHNjYWxlcy4KCkkgd2FzIHRoaW5raW5nIHRoYXQgaXQncyBub3QgcXVpdGUgcmlnaHQgdG8gZG8geW91ciBzdGFuZGFyZCAic2lnbmlmaWNhbmNlIiB0ZXN0IG9uIHRoaXMgY29ycmVsYXRpb24sIGFzIHRoZXNlIHByZWRpY3RlZC9vYnNlcnZlZCBjaGFuZ2Ugc2NvcmVzIGFyZW4ndCB2YWx1ZXMgc2FtcGxlZCBmcm9tIGEgcG9wdWxhdGlvbiBvZiB2YXJpYWJsZXMuIEluc3RlYWQsIHRoZXkgcmVwcmVzZW50IHRoZWlyIG93biBwb3B1bGF0aW9uLCBidXQgdGhlaXIgbWVhc3VyZW1lbnQgaXMgdW5jZXJ0YWluLCB3aXRoIHRoYXQgdW5jZXJ0YWludHkgY29taW5nIGZyb20gdGhlIHBhcnRpY2lwYW50LWxldmVsIGRhdGEuCgpBcyBJIHJlZmxlY3Qgb24gdGhpcyBJJ20gcG90ZW50aWFsbHkgYSBiaXQgb3V0IG9mIG15IGRlcHRoLCBzdGF0aXN0aWNhbGx5LiBCdXQgdGhlIGlkZWEgd2FzIEkgd291bGQgdGFrZSBib290c3RyYXAgc2FtcGxlcyBvZiB0aGUgZGF0YSwgbWFrZSBtb2RlbCBwcmVkaWN0aW9ucyBmb3IgZWFjaCwgdGhlbiBjYWxjdWxhdGUgdGhlIGNvcnJlbGF0aW9uIHdpdGggb2J0YWluZWQgdmFsdWVzLgoKVGhlIHJlc3VsdHMgZ2l2ZSBhIGJpdCBtb3JlIGNvbmZpZGVuY2UgYWJvdXQgdGhlIGVzdGltYXRlIHRoYW4geW91J2QgaGF2ZSBmcm9tIHRoZSBDSSB5b3UnZCBnZXQganVzdCB0cmVhdGluZyB0aGUgMTMgcG9pbnRzIGFzIGEgc2FtcGxlIGZyb20gYSBwb3B1bGF0aW9uICguMzAzIHRvIC45MTQpLgoKYGBge3J9CiMgd2F0Y2ggb3V0ISB0aGlzIHRha2VzIGEgZ29vZCAyMCBtaW4gdG8gcnVuIC4uLgoKdmFycyA8LSBkX3Njb3JlZCAlPiUgc2VsZWN0KHNjYWxlKSAlPiUgZmlsdGVyKHNjYWxlIT0iZGlzZWFzZVNldmVyZSIpICU+JSBkaXN0aW5jdCgpCgpib290X24gPC0gNTAwCml0ZXJzIDwtIDE6Ym9vdF9uCmNvcnMgPC0gcmVwKE5BLGJvb3RfbikKCmRfc2NvcmVkX3dpZGUgPC0gZF9zY29yZWQgJT4lCiAgZmlsdGVyKGNvbmRpdGlvbj09ImRpc2Vhc2VSaXNrIikgJT4lCiAgdW5pdGUoYWxsLCBzY2FsZSwgcGhhc2UpICU+JQogIHNwcmVhZChhbGwsIE1lYW4pCgoKCgpmb3IgKGkgaW4gaXRlcnMpIHsKICAKICAjIHJlc2FtcGxlIGRfc2NvcmVkIGFzIGRfYm9vdAogIGRfYm9vdCA8LSBzYW1wbGVfbihkX3Njb3JlZF93aWRlLCBzaXplID0gbnJvdyhkX3Njb3JlZF93aWRlKSwgcmVwbGFjZT1UUlVFKQogIAogIHgxIDwtIGFzLmRhdGEuZnJhbWUodChjb2xNZWFucyhkX2JuKSkpCiAgeDIgPC0geDEKICAKICAjIGNhbGN1bGF0ZSBtZWFuIGZyb20gZF9ib290CiAgZGlzZWFzZVNldmVyZU1lYW4wIDwtIGRfYm9vdCAlPiUgCiAgICBzdW1tYXJpemUobWVhbj1tZWFuKGRpc2Vhc2VTZXZlcmVfcHJlKSkgJT4lCiAgICBhcy5udW1lcmljKCkKICAKICBkaXNlYXNlU2V2ZXJlTWVhbjEgPC0gZF9ib290ICU+JSAKICAgIHN1bW1hcml6ZShtZWFuPW1lYW4oZGlzZWFzZVNldmVyZV9wb3N0KSkgJT4lCiAgICBhcy5udW1lcmljKCkKICAKICB4MVssImRpc2Vhc2VTZXZlcmUiXSA8LSBkaXNlYXNlU2V2ZXJlTWVhbjAKICB4MlssImRpc2Vhc2VTZXZlcmUiXSA8LSBkaXNlYXNlU2V2ZXJlTWVhbjEKICAKICAjIG1ha2UgcHJlZGljdGlvbnMKICBwcmVkMCA8LSBtYWtlX3ByZWRpY3Rpb25zKGphZ3NfbW9kZWwsIHgxLCBhcy5jaGFyYWN0ZXIodmFycyRzY2FsZSksIGl0ZXIgPSA1KjFlNCkKICBwcmVkMSA8LSBtYWtlX3ByZWRpY3Rpb25zKGphZ3NfbW9kZWwsIHgyLCBhcy5jaGFyYWN0ZXIodmFycyRzY2FsZSksIGl0ZXIgPSA1KjFlNCkKICAKICBwcmVkMCA8LSBwcmVkMCAlPiUgYXNfdGliYmxlKCkgJT4lIGdhdGhlcihzY2FsZSwgdmFsdWUpICU+JSBtdXRhdGUocGhhc2U9InByZSIpCiAgcHJlZDEgPC0gcHJlZDEgJT4lIGFzX3RpYmJsZSgpICU+JSBnYXRoZXIoc2NhbGUsIHZhbHVlKSAlPiUgbXV0YXRlKHBoYXNlPSJwb3N0IikKICAKICBwcmVkaWN0aW9ucyA8LSBwcmVkMCAlPiUgCiAgICBiaW5kX3Jvd3MocHJlZDEpIAogIAogICMgY2FsY3VsYXRlIG9ic2VydmVkIGNoYW5nZSBzY29yZXMKICBvYnNNZWFucyA8LSBkX2Jvb3QgJT4lCiAgICBtdXRhdGUoaWQgPSByb3dfbnVtYmVyKCkpICU+JSAjIGFsbCB0aGlzIHRvIGdldCBhIHVuaXF1ZSBJRCBmb3IgZWFjaCAicGFydGljaXBhbnQiCiAgICBnYXRoZXIoc2NhbGUsIE1lYW4sZGlzZWFzZVJhcmVfcG9zdDp2YWNjVG94X3ByZSkgJT4lIAogICAgbXV0YXRlKHBoYXNlID0gaWZlbHNlKGdyZXBsKCJfcG9zdCIsIHNjYWxlKSwicG9zdCIsInByZSIpKSAlPiUKICAgIG11dGF0ZShzY2FsZSA9IGdzdWIoIl8uKiIsIiIsc2NhbGUpKSAlPiUKICAgIHNwcmVhZChwaGFzZSxNZWFuKSAlPiUKICAgIG11dGF0ZShjaGFuZ2UgPSBwb3N0LXByZSkgJT4lCiAgICBncm91cF9ieShzY2FsZSkgJT4lCiAgICBzdW1tYXJpemUoY2hhbmdlX3Njb3JlID0gbWVhbihjaGFuZ2UpLAogICAgICAgICAgc3RkX2Vycm9yID0gc3RkZXJyKGNoYW5nZSkpICU+JQogICAgZmlsdGVyKHNjYWxlIT0iZGlzZWFzZVNldmVyZSIpICU+JQogICAgbXV0YXRlKHR5cGU9Im9ic2VydmVkIikKICAKICBwcmVkTWVhbnMgPC0gcHJlZGljdGlvbnMgJT4lIAogICAgZ3JvdXBfYnkoc2NhbGUscGhhc2UpICU+JSAKICAgIHN1bW1hcml6ZShtZWFuX3Jlc3AgPSBtZWFuKHZhbHVlKSkgJT4lCiAgICBtdXRhdGUodHlwZT0icHJlZGljdGVkIikgJT4lCiAgICBzcHJlYWQocGhhc2UsIG1lYW5fcmVzcCkgJT4lCiAgICAjIGdyb3VwX2J5KHNjYWxlKSAlPiUKICAgIG11dGF0ZShjaGFuZ2Vfc2NvcmUgPSBwb3N0IC0gcHJlLAogICAgICAgICAgICAgIHN0ZF9lcnJvciA9IDApCiAgIyBjb21iaW5lIHdpdGggcHJlZGljdGlvbnMKICBkX3NpbSA8LSBvYnNNZWFucyAlPiUgYmluZF9yb3dzKHByZWRNZWFucykKICAKICBzaW1NZWFuIDwtIGRfc2ltICU+JSAKICAgIHNlbGVjdCgtcG9zdCwtcHJlLCAtc3RkX2Vycm9yKSAlPiUKICAgIGZpbHRlcihzY2FsZSE9ImRpc2Vhc2VTZXZlcmUiKSAlPiUKICAgIGdyb3VwX2J5KHR5cGUsc2NhbGUpICU+JQogICAgc3ByZWFkKHR5cGUsIGNoYW5nZV9zY29yZSkKICAKICBjb3JzW2ldIDwtIGNvcihzaW1NZWFuJHByZWRpY3RlZCwgc2ltTWVhbiRvYnNlcnZlZCkKfQoKCmBgYAoKVGhlIG1lYW4gY29ycmVsYXRpb24gdmFsdWUgaXMgYHIgcm91bmQobWVhbihjb3JzKSwzKWAgYW5kIHRoZSBib290c3RyYXBwZWQgOTUlIENJIGRvZXMgbm90IGluY2x1ZGUgemVyby4gU28sIG1pbmltYWxseSwgdGhlIG1vZGVsIGlzIHBpY2tpbmcgdXAgb24gX3NvbWV0aGluZ18uIEJlbG93IGlzIGEgaGlzdG9ncmFtIG9mIGNvcnJlbGF0aW9uIHZhbHVlcywgd2l0aCBhIGxpbmUgbWFya2luZyB0aGUgb2JzZXJ2ZWQgY29ycmVsYXRpb24gaW4gdGhlIG9yaWdpbmFsIHNhbXBsZS4KCmBgYHtyfQptZWFuKGNvcnMpCnF1YW50aWxlKGNvcnMsIGMoLjAyNSwuOTc1KSkKCmhpc3QoY29ycywgYnJlYWtzID0gMjApCmFibGluZSh2ID0gLjc3NiwgY29sPSJyZWQiKQpgYGAKCiMjIE1vZGVsaW5nIHBhcnRpY2lwYW50LXdpc2UgcHJlZGljdGlvbnMKCldlIGNhbiBhbHNvIGFzayBpZiB0aGUgZGlmZmVyZW5jZSBmcm9tIHByZSB0byBwb3N0LXRlc3QgZm9yIGluZGl2aWR1YWwgcGFydGljaXBhbnRzIGFyZSBzaW1pbGFyIHRvIHdoYXQgd2Ugd291bGQgZXhwZWN0IGFjY29yZGluZyB0byB0aGUgbW9kZWwuIFdoYXQgSSdtIGRvaW5nIGhlcmUgaXMgZ2VuZXJhdGluZyBtb2RlbCBwcmVkaWN0aW9ucyBiYXNlZCBvbiBwcmV0ZXN0IGRpc2Vhc2VTZXZlcmUgYW5kIHBvc3R0ZXN0IGRpc2Vhc2VTZXZlcmUgcmF0aW5ncy4gVGhlbiwgY29tcHV0aW5nIGEgcHJlZGljdGVkIGNoYW5nZSBzY29yZSBmb3IgZWFjaCBwYXJ0aWNpcGFudCBvbiBlYWNoIHJlbWFpbmluZyBzY2FsZSwgYW5kIGFkZGluZyB0aGF0IHRvIHRoZWlyIHByZXRlc3Qgc2NvcmVzIHRvIHByZWRpY3QgdGhlaXIgcG9zdHRlc3Qgc2NvcmVzLiBJJ20gdGhlbiB0cnVuY2F0aW5nIHdpdGhpbiB0aGUgYWxsb3dlZCByYW5nZSBvZiAtMyB0byAzLCBhbmQgcmVjYWxjdWxhdGluZyBhIHByZWRpY3RlZCBjaGFuZ2Ugc2NvcmUuICAKCgoKYGBge3J9CnNldC5zZWVkKDEyMykKCm5TYW1wID0gMWU1CnZhcnMgPC0gZF9zY29yZWQgJT4lIHNlbGVjdChzY2FsZSkgJT4lIGZpbHRlcihzY2FsZSE9ImRpc2Vhc2VTZXZlcmUiKSAlPiUgZGlzdGluY3QoKSAlPiUgbXV0YXRlKHNjYWxlPWFzLmNoYXJhY3RlcihzY2FsZSkpCgojIEkgYWxzbyB0cmllZCBsaW1pdGluZyB0aGUgYW5hbHlzaXMgdG8gbG93ZXItc2NvcmluZyBQcywgdGhhdCBpcyB3aXRoIHZhY2NJbnRlbnQgc2NvcmVzIDwgMi4gSSBkaWRuJ3QgZG8gaXQgcXVpdGUgcmlnaHQgaW4gdGhlIGNvZGUgYmVsb3cgYnV0IGl0IGRvZXNuJ3QgbG9vayBwcm9taXNpbmcgKDIwMTgtMDQtMjgpLgoKb2JzU2NvcmVzIDwtIGRfc2NvcmVkICU+JQogIGZpbHRlcihjb25kaXRpb249PSJkaXNlYXNlUmlzayIpICU+JQogICMgc3ByZWFkKHNjYWxlLE1lYW4pICU+JSAjIGF2b2lkIGhpZ2ggc2NvcmluZyBwcwogICMgZ3JvdXBfYnkod29ya2VySWQpICU+JSAjIGF2b2lkIGhpZ2ggc2NvcmluZyBwcwogICMgZmlsdGVyKCFhbnkodmFjY0ludGVudCA+IDIpKSAlPiUgIyBhdm9pZCBoaWdoIHNjb3JpbmcgcHMKICAjIGdhdGhlcihzY2FsZSwgTWVhbiwgdmFjY0ludGVudDpwYXJlbnRFeHBlcnQpICU+JSAjIGF2b2lkIGhpZ2ggc2NvcmluZyBwcwogICMgdW5ncm91cCgpICMgYXZvaWQgaGlnaCBzY29yaW5nIHBzCiAgbXV0YXRlKHR5cGU9Im9ic2VydmVkIikgJT4lCiAgc2VsZWN0KC1jb25kaXRpb24pICU+JQogIG11dGF0ZV9pZihpcy5mYWN0b3IsYXMuY2hhcmFjdGVyKQoKZF9zaW1fcHdpc2UgPC0gb2JzU2NvcmVzICU+JQogIGZpbHRlcihwaGFzZT09InBvc3QiKSAlPiUKICAjIG11dGF0ZSh0eXBlPSJwcmVkaWN0ZWQiKSAlPiUKICBtdXRhdGVfaWYoaXMuZmFjdG9yLGFzLmNoYXJhY3RlcikKICAKcGFydGljaXBhbnRfaWRzIDwtIHVuaXF1ZShkX3NpbV9wd2lzZSR3b3JrZXJJZCkKCmZvciAoaWQgaW4gcGFydGljaXBhbnRfaWRzKSB7ICAKICAKICBwX2RhdGEgPC0gb2JzU2NvcmVzICU+JQogICAgZmlsdGVyKHdvcmtlcklkID09IGlkKQogIAogIHBfZGF0YV9wcmUgPC0gcF9kYXRhICU+JQogICAgZmlsdGVyKHBoYXNlID09ICJwcmUiKQogIAogIHBfZGF0YV9wb3N0IDwtIHBfZGF0YSAlPiUKICAgIGZpbHRlcihwaGFzZSA9PSAicG9zdCIpCgogIG9ic19wcmUgPC0gcF9kYXRhX3ByZSAlPiUKICAgIGZpbHRlcihzY2FsZT09ImRpc2Vhc2VTZXZlcmUiKSAlPiUKICAgIC4kTWVhbgoKICBvYnNfcG9zdCA8LSBwX2RhdGFfcG9zdCAlPiUKICAgIGZpbHRlcihzY2FsZT09ImRpc2Vhc2VTZXZlcmUiKSAlPiUKICAgIC4kTWVhbgogIAogIHByZWRfcHJlIDwtIG1ha2VfcHJlZGljdGlvbnMoamFnc19tb2RlbCwgZGF0YS5mcmFtZShkaXNlYXNlU2V2ZXJlID0gb2JzX3ByZSksIGFzLmNoYXJhY3Rlcih2YXJzJHNjYWxlKSxpdGVyPTFlNCkKICBwcmVkX3Bvc3QgPC0gbWFrZV9wcmVkaWN0aW9ucyhqYWdzX21vZGVsLCBkYXRhLmZyYW1lKGRpc2Vhc2VTZXZlcmUgPSBvYnNfcG9zdCksIGFzLmNoYXJhY3Rlcih2YXJzJHNjYWxlKSxpdGVyPTFlNCkKICBwcmVkX2NoYW5nZSA8LSBwcmVkX3Bvc3QgLSBwcmVkX3ByZQogIAogIHByZWRfcG9zdF9maW5hbCA8LSAocF9kYXRhX3ByZSAlPiUgCiAgICBzZWxlY3Qoc2NhbGUsTWVhbikgJT4lIAogICAgc3ByZWFkKHNjYWxlLE1lYW4pKSArIHByZWRfY2hhbmdlCiAgCiAgcHJlZCA8LSBwcmVkX3Bvc3RfZmluYWwgJT4lCiAgICBnYXRoZXIoc2NhbGUsIE1lYW4pICU+JQogICAgbXV0YXRlKE1lYW4gPSB0cnVuY2F0ZV90b19yYW5nZShNZWFuLC0zLDMpKSAlPiUKICAgIG11dGF0ZSgKICAgICAgd29ya2VySWQgPSBpZCwKICAgICAgcGhhc2UgPSAicG9zdCIsCiAgICAgIHR5cGUgPSAicHJlZGljdGVkIgogICAgICApCiAgCgogIGRfc2ltX3B3aXNlIDwtIGJpbmRfcm93cyhkX3NpbV9wd2lzZSwgcHJlZCkKICAjIGRfc2ltX3B3aXNlW2luZGV4LF0gPC0gcHJlZFsxLF0KfQoKYGBgCgpTbyBwcmVkaWN0aW5nIHBvc3R0ZXN0IHNjb3JlcyBmcm9tIHByZXRlc3Qgc2NvcmVzICsgcHJlZGljdGVkIGNoYW5nZSBzY29yZXMsIHdlIGRvIHByZXR0eSB3ZWxsLiBUaGUgY29ycmVsYXRpb25zIG92ZXJhbGwgc2VlbSBnb29kLCBidXQgdGhleSBhcmUgbW9zdGx5IGRyaXZlbiBieSB0aGUga25vd2VsZGdlIG9mIHRoZSBwcmV0ZXN0IHNjb3Jlcy4KCmBgYHtyfQpkZiA8LSBiaW5kX3Jvd3MoZF9zaW1fcHdpc2UsIG9ic1Njb3JlcyAlPiUgZmlsdGVyKHBoYXNlPT0icHJlIikpICU+JSBmaWx0ZXIoc2NhbGUhPSJkaXNlYXNlU2V2ZXJlIikKCmRmICU+JQogIGZpbHRlcihwaGFzZSA9PSAicG9zdCIpICU+JQogIHNwcmVhZCh0eXBlLE1lYW4pICU+JQogIGdncGxvdChhZXMoeD1wcmVkaWN0ZWQsIHk9b2JzZXJ2ZWQpKSArCiAgZ2VvbV9wb2ludChzaGFwZT0xLCBzaXplPS41LCBjb2xvcj0iZGFya3R1cnF1b2lzZSIpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpICsKICBmYWNldF93cmFwKH5zY2FsZSkKCmBgYAoKYGBge3J9CnNpbV9yZXMgPC0gZGYgJT4lIHNwcmVhZCh0eXBlLE1lYW4pICU+JSBmaWx0ZXIocGhhc2UgPT0gInBvc3QiKQoKc2ltX3JlcyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBwcmVkaWN0ZWQsIHkgPSBvYnNlcnZlZCwgY29sb3IgPSBzY2FsZSkpICsKICBnZW9tX2ppdHRlcihzaGFwZT0xKSArCiAgIyBnZW9tX3Ntb290aChtZXRob2Q9ImxtIiwgYWxwaGEgPSAuNSkgKwogICMgZ2VvbV9zbW9vdGgoYWVzKHg9cHJlZGljdGVkLCB5ID0gb2JzZXJ2ZWQpLCBpbmhlcml0LmFlcyA9IEZBTFNFLCBtZXRob2Q9ImxtIikgKwogIHRoZW1lX21pbmltYWwoKQoKc2ltX3JlcyAlPiUgCiAgZ3JvdXBfYnkoc2NhbGUpICU+JQogIHN1bW1hcml6ZShjb3IgPSBjb3IocHJlZGljdGVkLG9ic2VydmVkKSkKYGBgCgpUaGF0J3MgZXZpZGVuY2VkIGJ5IHRoZSBhYnlzbWFsIHBlcmZvcm1hbmNlIG9mIHRoZSBtb2RlbCB0byBwcmVkaWN0IGluZGl2aWR1YWwgcGFydGljaXBhbnRzJyBjaGFuZ2Ugc2NvcmVzLiBJIGFtIG5vdCBxdWl0ZSBzdXJlIGhvdyB0byBleHBsYWluIHRoZW0gYmV5b25kIHRoZSBmYWN0IHRoYXQgdGhlIGRlZ3JlZSBvZiBwcmVkaWN0ZWQgY2hhbmdlIGlzIGNsZWFybHkgZGVwZW5kZW50IHVwb24gdGhlIHByaW9yIHNjb3JlLiBUaGF0IGlzLCB3ZSBleHBlY3Qgc21hbGxlciBpbmNyZWFzZXMgd2l0aCBoaWdoIHNjb3JlcyBhbmQgc21hbGxlciBkZWNyZWFzZXMgd2l0aCBsb3cgc2NvcmVzLCBldGMuICBJbiB0aGUgY2FzZSBvZiBzY2FsZXMgd2hlcmUgdGhlIG1vZGVsIHByZWRpY3Rpb25zIGFyZSBORUdBVElWRUxZIGNvcnJlbGF0ZWQsIEkgdGhpbmsgdGhhdCBtaWdodCBiZSB0aGUgZXhwbGFuYXRpb24uIFJpZ2h0IG5vdyB0aGUgb25seSB0aGluZyBpbiB0aGUgbW9kZWwgdG8gZ3VhcmQgYWdhaW5zdCB0aGF0IGlzIGEgc2ltcGx5IHRydW5jYXRpb24gb24gdGhlIHBvc3R0ZXN0IHByZWRpY3Rpb25zLCBib3VuZGluZyB0aGVtIHdpdGhpbiB0aGUgcmFuZ2Ugb2YgLTMgdG8gMy4gKGJ1dCB0aGF0IGRvZXNuJ3Qgc2VlbSB0byBhZmZlY3QgdGhlIHByZWRpY3Rpb24vZml0IHZlcnkgbXVjaCkKCmBgYHtyfQpkZiAlPiUKICBiaW5kX3Jvd3Mob2JzU2NvcmVzICU+JSBmaWx0ZXIocGhhc2U9PSJwcmUiKSAlPiUgbXV0YXRlKHR5cGU9InByZWRpY3RlZCIpICU+JSBmaWx0ZXIoc2NhbGUhPSJkaXNlYXNlU2V2ZXJlIikpICU+JQogIHNwcmVhZChwaGFzZSwgTWVhbikgJT4lCiAgbXV0YXRlKGRpZmY9cG9zdC1wcmUpICU+JQogIGdyb3VwX2J5KHdvcmtlcklkLCBzY2FsZSwgdHlwZSkgJT4lCiAgc3VtbWFyaXplKGRpZmY9Zmlyc3QoZGlmZikpICU+JQogIGdyb3VwX2J5KHdvcmtlcklkKSAlPiUKICBzcHJlYWQodHlwZSwgZGlmZikgJT4lCiAgZ2dwbG90KGFlcyh4PXByZWRpY3RlZCwgeT1vYnNlcnZlZCkpICsKICBnZW9tX3BvaW50KHNoYXBlPTEsIHNpemU9LjUsIGNvbG9yPSJkYXJrdHVycXVvaXNlIikgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArCiAgZmFjZXRfd3JhcCh+c2NhbGUpCmBgYAoKQXZlcmFnZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHByZWRpY3RlZCBhbmQgb2JzZXJ2ZWQgYWNyb3NzIGFsbCBzY2FsZXMgaXMgYXBwcm94aW1hdGVseSByID0gLjEKCmBgYHtyfQpkZiAlPiUKICBiaW5kX3Jvd3Mob2JzU2NvcmVzICU+JSBmaWx0ZXIocGhhc2U9PSJwcmUiKSAlPiUgbXV0YXRlKHR5cGU9InByZWRpY3RlZCIpICU+JSBmaWx0ZXIoc2NhbGUhPSJkaXNlYXNlU2V2ZXJlIikpICU+JQogIHNwcmVhZChwaGFzZSwgTWVhbikgJT4lCiAgbXV0YXRlKGRpZmY9cG9zdC1wcmUpICU+JQogIGdyb3VwX2J5KHdvcmtlcklkLCBzY2FsZSwgdHlwZSkgJT4lCiAgc3VtbWFyaXplKGRpZmY9Zmlyc3QoZGlmZikpICU+JQogIGdyb3VwX2J5KHNjYWxlKSAlPiUKICBzcHJlYWQodHlwZSwgZGlmZikgJT4lCiAgc3VtbWFyaXplKHIgPSBjb3IocHJlZGljdGVkLG9ic2VydmVkKSkKYGBgCgpTbyB0aGUgbW9kZWwgZmFpbHMgbWlzZXJhYmx5IGF0IGluZGl2aWR1YWwtbGV2ZWwgcHJlZGljdGlvbnMsIGNhcHR1cmluZyBjaGFuZ2VzIG9ubHkgYXQgdGhlIHBvcHVsYXRpb24gbGV2ZWwuCgojIEJhc2VsaW5lIG1vZGVsIChuYcOvdmUgYmF5ZXMpCgpUbyBldmFsdWF0ZSB0aGUgcGVyZm9ybWFuY2Ugb2Ygb3VyIG1vZGVsLCB3ZSBzaG91bGQgY29tcGFyZSBpdCB0byBzb21ldGhpbmcgZWxzZS4gSSB0aGluayBhIGdvb2QgYmFzZWxpbmUgY2FuZGlkYXRlIGlzIGEgIm5hw692ZSBiYXllcyIgb3IgbmHDr3ZlIGNhdXNhbCBtb2RlbC0td2hlcmUgZGlzZWFzZVNldmVyZSBwcmVkaWN0cyBhbGwgb3RoZXIgYmVsaWVmcy4gVGhpcyBjb3VsZCBiZSBzaW11bGF0ZWQgYnkgYSBzZXJpZXMgb2YgbGluZWFyIHJlZ3Jlc3Npb25zLCBidXQgSSB0aGluayBpdCB3aWxsIGFjdHVhbGx5IGJlIGVhc2llciB0byBwdXQgaXQgaW50byBoeWRlbmV0LgoKVmlzdWFsbHkgLi4uCgpgYGB7cn0KdmFycyA8LSBkX3Njb3JlZCAlPiUgc2VsZWN0KHNjYWxlKSAlPiUgZmlsdGVyKHNjYWxlIT0iZGlzZWFzZVNldmVyZSIpICU+JSBkaXN0aW5jdCgpCgojIG5hw692ZSBjYXVzYWwgbW9kZWwsIGRpc2Vhc2VTZXZlcmUtLT4gYWxsIChlcXVpdmFsZW50IGNoYW5nZSBzY29yZSBwcmVkaWN0aW9uKQpuYl9hcmNzIDwtIGRhdGEuZnJhbWUoZnJvbSA9IHJlcCgiZGlzZWFzZVNldmVyZSIsIDEzKSwgdG8gPSB2YXJzJHNjYWxlKQoKIyAjIHJlZ3Jlc3Npb24gcHJlZGljdGluZyB2YWNjSW50ZW50IChwb29yIGNoYW5nZSBzY29yZSBwcmVkaWN0aW9uKQojIG5iX2FyY3MgPC0gZGF0YS5mcmFtZShmcm9tID0gbmFtZXMoZF9ibiksIHRvID0gcmVwKCJ2YWNjSW50ZW50IiwgMTQpKSAlPiUgZmlsdGVyKGZyb20hPSJ2YWNjSW50ZW50IikKCiMgIyBuYcOvdmUgYmF5ZXMsIHZhY2MgaW50ZW50ICJjbGFzc2lmaWVyIiAoc2xpZ2h0bHkgd2Vha2VyIGNoYW5nZSBzY29yZSBwcmVkaWN0aW9uKQojIG5iX2FyY3MgPC0gZGF0YS5mcmFtZSh0byA9IG5hbWVzKGRfYm4pLCBmcm9tID0gcmVwKCJ2YWNjSW50ZW50IiwgMTQpKSAlPiUgZmlsdGVyKHRvIT0idmFjY0ludGVudCIpCgoKaHlkZV9uYiA8LSBkZl90b19oeWRlX3N0cmluZyhuYl9hcmNzKQpuYl9oeWRlX25ldHdvcmsgPC0gSHlkZU5ldHdvcmsoYXMuZm9ybXVsYShoeWRlX25iKSwgZGF0YT1hcy5kYXRhLmZyYW1lKGRfYm4pKQoKbmJfamFnc19tb2RlbCA8LSB3cml0ZU5ldHdvcmtNb2RlbChuYl9oeWRlX25ldHdvcmspCgpwbG90KG5iX2h5ZGVfbmV0d29yaykKYGBgCgoKYGBge3J9CgoKCngxIDwtIGFzLmRhdGEuZnJhbWUodChjb2xNZWFucyhkX2JuKSkpCngyIDwtIGFzLmRhdGEuZnJhbWUodChjb2xNZWFucyhkX2JuKSkpCgp4MVssImRpc2Vhc2VTZXZlcmUiXSA8LSBkaXNlYXNlU2V2ZXJlTWVhbjAKeDJbLCJkaXNlYXNlU2V2ZXJlIl0gPC0gZGlzZWFzZVNldmVyZU1lYW4xCgpwcmVkMF9uYiA8LSBtYWtlX3ByZWRpY3Rpb25zKG5iX2phZ3NfbW9kZWwsIHgxLCBhcy5jaGFyYWN0ZXIodmFycyRzY2FsZSksaXRlcj0xZTUpCnByZWQxX25iIDwtIG1ha2VfcHJlZGljdGlvbnMobmJfamFnc19tb2RlbCwgeDIsIGFzLmNoYXJhY3Rlcih2YXJzJHNjYWxlKSxpdGVyPTFlNSkKCnByZWQwX25iIDwtIHByZWQwX25iICU+JSBhc190aWJibGUoKSAlPiUgZ2F0aGVyKHNjYWxlLCB2YWx1ZSkgJT4lIG11dGF0ZShwaGFzZSA9ICJwcmUiKQpwcmVkMV9uYiA8LSBwcmVkMV9uYiAlPiUgYXNfdGliYmxlKCkgJT4lIGdhdGhlcihzY2FsZSwgdmFsdWUpICU+JSBtdXRhdGUocGhhc2UgPSAicG9zdCIpCgpwcmVkaWN0aW9uc19uYiA8LSBwcmVkMF9uYiAlPiUgCiAgYmluZF9yb3dzKHByZWQxX25iKSAKCm9ic01lYW5zIDwtIGRfc2NvcmVkICU+JSAKICBmaWx0ZXIoY29uZGl0aW9uID09ICJkaXNlYXNlUmlzayIpICU+JSAKICBzcHJlYWQocGhhc2UsIE1lYW4pICU+JQogIG11dGF0ZShzY29yZSA9IHBvc3QgLSBwcmUpICU+JQogIGdyb3VwX2J5KHNjYWxlKSAlPiUKICBzdW1tYXJpemUoY2hhbmdlX3Njb3JlID0gbWVhbihzY29yZSksCiAgICAgICAgICAgIHN0ZF9lcnJvciA9IHN0ZGVycihzY29yZSkpICU+JQogIGZpbHRlcihzY2FsZSE9ImRpc2Vhc2VTZXZlcmUiKSAlPiUKICBtdXRhdGUodHlwZT0ib2JzZXJ2ZWQiKQoKcHJlZE1lYW5zX25iIDwtIHByZWRpY3Rpb25zX25iICU+JSAKICBncm91cF9ieShzY2FsZSxwaGFzZSkgJT4lIAogIHN1bW1hcml6ZShtZWFuX3Jlc3AgPSBtZWFuKHZhbHVlKSkgJT4lCiAgbXV0YXRlKHR5cGU9InByZWRpY3RlZCIpICU+JQogIHNwcmVhZChwaGFzZSwgbWVhbl9yZXNwKSAlPiUKICAjIGdyb3VwX2J5KHNjYWxlKSAlPiUKICBtdXRhdGUoY2hhbmdlX3Njb3JlID0gcG9zdCAtIHByZSwKICAgICAgICAgICAgc3RkX2Vycm9yID0gMCkKCmRfc2ltX25iIDwtIG9ic01lYW5zICU+JSBiaW5kX3Jvd3MocHJlZE1lYW5zX25iKQoKZF9zaW1fbmIgJT4lCiAgbXV0YXRlKAogICAgICAgICBVTCA9IGNoYW5nZV9zY29yZSArIHN0ZF9lcnJvcioxLjk2LAogICAgICAgICBMTCA9IGNoYW5nZV9zY29yZSAtIHN0ZF9lcnJvcioxLjk2CiAgICAgICAgICkgJT4lCiAgZ2dwbG90KGFlcyh5ID0gcmVvcmRlcihzY2FsZSwgY2hhbmdlX3Njb3JlKSwKICAgICAgICAgICAgIHggPSBjaGFuZ2Vfc2NvcmUsCiAgICAgICAgICAgICB4bWF4ID0gVUwsIAogICAgICAgICAgICAgeG1pbiA9IExMLCAKICAgICAgICAgICAgIGNvbG9yID0gdHlwZSkpICsKICBnZW9tX3BvaW50KHNoYXBlPTE3LCBzaXplPTMpICsKICBnZW9tX2Vycm9yYmFyaChoZWlnaHQ9MCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpCmBgYAoKYGBge3J9CnNpbU1lYW5fbmIgPC0gZF9zaW1fbmIgJT4lIAogIHNlbGVjdCgtcG9zdCwtcHJlLCAtc3RkX2Vycm9yKSAlPiUKICBmaWx0ZXIoc2NhbGUhPSJkaXNlYXNlU2V2ZXJlIikgJT4lCiAgZ3JvdXBfYnkodHlwZSxzY2FsZSkgJT4lCiAgc3ByZWFkKHR5cGUsIGNoYW5nZV9zY29yZSkKCgpzaW1NZWFuQ29yIDwtIGNvcihzaW1NZWFuX25iJHByZWRpY3RlZCwgc2ltTWVhbl9uYiRvYnNlcnZlZCkgJT4lIHJvdW5kKDMpCgpzaW1NZWFuX25iICU+JQogIGdncGxvdChhZXMoeD1wcmVkaWN0ZWQsIHk9b2JzZXJ2ZWQpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3RleHQoYWVzKHg9LS4xLCB5PSAuMiwgbGFiZWw9cGFzdGUoInIgPSIsc2ltTWVhbkNvcikpKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpICsKICBsYWJzKHRpdGxlPSJBdmVyYWdlIGRpZmZlcmVuY2Ugc2NvcmVzIikgKwogIHRoZW1lKGFzcGVjdC5yYXRpbyA9IDEpCmBgYAoKQW5kIHBlcmZvcm1hbmNlIGlzIGVzc2VudGlhbGx5IGlkZW50aWNhbC4gVGhhdCBpcywgX19pZiB3ZSBqdXN0IG5hw692ZWx5IGFzc3VtZSBkaXNlYXNlIHNldmVyaXR5IGRyaXZlcyBhbGwgYmVsaWVmcyBhbmQgd2UgZ2V0IGp1c3QgYWJvdXQgYXMgZ29vZCBhIHByZWRpY3Rpb24gYXMgb3VyIG1vcmUgc29waGlzdGljYXRlZCBtb2RlbC5fXwoKYGBge3J9CnNldC5zZWVkKDEyMykKCm5TYW1wID0gMWU1CnZhcnMgPC0gZF9zY29yZWQgJT4lIHNlbGVjdChzY2FsZSkgJT4lIGZpbHRlcihzY2FsZSE9ImRpc2Vhc2VTZXZlcmUiKSAlPiUgZGlzdGluY3QoKSAlPiUgbXV0YXRlKHNjYWxlPWFzLmNoYXJhY3RlcihzY2FsZSkpCgoKCm9ic1Njb3JlcyA8LSBkX3Njb3JlZCAlPiUKICBmaWx0ZXIoY29uZGl0aW9uPT0iZGlzZWFzZVJpc2siKSAlPiUKICAjIHNwcmVhZChzY2FsZSxNZWFuKSAlPiUgIyBhdm9pZCBoaWdoIHNjb3JpbmcgcHMKICAjIGdyb3VwX2J5KHdvcmtlcklkKSAlPiUgIyBhdm9pZCBoaWdoIHNjb3JpbmcgcHMKICAjIGZpbHRlcighYW55KHZhY2NJbnRlbnQgPiAyKSkgJT4lICMgYXZvaWQgaGlnaCBzY29yaW5nIHBzCiAgIyBnYXRoZXIoc2NhbGUsIE1lYW4sIHZhY2NJbnRlbnQ6cGFyZW50RXhwZXJ0KSAlPiUgIyBhdm9pZCBoaWdoIHNjb3JpbmcgcHMKICAjIHVuZ3JvdXAoKSAjIGF2b2lkIGhpZ2ggc2NvcmluZyBwcwogIG11dGF0ZSh0eXBlPSJvYnNlcnZlZCIpICU+JQogIHNlbGVjdCgtY29uZGl0aW9uKSAlPiUKICBtdXRhdGVfaWYoaXMuZmFjdG9yLGFzLmNoYXJhY3RlcikKCmRfc2ltX3B3aXNlX25iIDwtIG9ic1Njb3JlcyAlPiUKICBmaWx0ZXIocGhhc2U9PSJwb3N0IikgJT4lCiAgIyBtdXRhdGUodHlwZT0icHJlZGljdGVkIikgJT4lCiAgbXV0YXRlX2lmKGlzLmZhY3Rvcixhcy5jaGFyYWN0ZXIpCiAgCnBhcnRpY2lwYW50X2lkcyA8LSB1bmlxdWUoZF9zaW1fcHdpc2VfbmIkd29ya2VySWQpCgpmb3IgKGlkIGluIHBhcnRpY2lwYW50X2lkcykgeyAgCiAgCiAgcF9kYXRhIDwtIG9ic1Njb3JlcyAlPiUKICAgIGZpbHRlcih3b3JrZXJJZCA9PSBpZCkKICAKICBwX2RhdGFfcHJlIDwtIHBfZGF0YSAlPiUKICAgIGZpbHRlcihwaGFzZSA9PSAicHJlIikKICAKICBwX2RhdGFfcG9zdCA8LSBwX2RhdGEgJT4lCiAgICBmaWx0ZXIocGhhc2UgPT0gInBvc3QiKQoKICBvYnNfcHJlIDwtIHBfZGF0YV9wcmUgJT4lCiAgICBmaWx0ZXIoc2NhbGU9PSJkaXNlYXNlU2V2ZXJlIikgJT4lCiAgICAuJE1lYW4KCiAgb2JzX3Bvc3QgPC0gcF9kYXRhX3Bvc3QgJT4lCiAgICBmaWx0ZXIoc2NhbGU9PSJkaXNlYXNlU2V2ZXJlIikgJT4lCiAgICAuJE1lYW4KICAKICBwcmVkX3ByZSA8LSBtYWtlX3ByZWRpY3Rpb25zKG5iX2phZ3NfbW9kZWwsIGRhdGEuZnJhbWUoZGlzZWFzZVNldmVyZSA9IG9ic19wcmUpLCBhcy5jaGFyYWN0ZXIodmFycyRzY2FsZSksaXRlcj0xZTQpCiAgcHJlZF9wb3N0IDwtIG1ha2VfcHJlZGljdGlvbnMobmJfamFnc19tb2RlbCwgZGF0YS5mcmFtZShkaXNlYXNlU2V2ZXJlID0gb2JzX3Bvc3QpLCBhcy5jaGFyYWN0ZXIodmFycyRzY2FsZSksaXRlcj0xZTQpCiAgcHJlZF9jaGFuZ2UgPC0gcHJlZF9wb3N0IC0gcHJlZF9wcmUKICAKICBwcmVkX3Bvc3RfZmluYWwgPC0gKHBfZGF0YV9wcmUgJT4lIAogICAgc2VsZWN0KHNjYWxlLE1lYW4pICU+JSAKICAgIHNwcmVhZChzY2FsZSxNZWFuKSkgKyBwcmVkX2NoYW5nZQogIAogIHByZWQgPC0gcHJlZF9wb3N0X2ZpbmFsICU+JQogICAgZ2F0aGVyKHNjYWxlLCBNZWFuKSAlPiUKICAgIG11dGF0ZShNZWFuID0gdHJ1bmNhdGVfdG9fcmFuZ2UoTWVhbiwtMywzKSkgJT4lCiAgICBtdXRhdGUoCiAgICAgIHdvcmtlcklkID0gaWQsCiAgICAgIHBoYXNlID0gInBvc3QiLAogICAgICB0eXBlID0gInByZWRpY3RlZCIKICAgICAgKQogIAoKICBkX3NpbV9wd2lzZV9uYiA8LSBiaW5kX3Jvd3MoZF9zaW1fcHdpc2VfbmIsIHByZWQpCiAgIyBkX3NpbV9wd2lzZVtpbmRleCxdIDwtIHByZWRbMSxdCn0KCmRmX25iIDwtIGJpbmRfcm93cyhkX3NpbV9wd2lzZV9uYiwgb2JzU2NvcmVzICU+JSBmaWx0ZXIocGhhc2U9PSJwcmUiKSkgJT4lIGZpbHRlcihzY2FsZSE9ImRpc2Vhc2VTZXZlcmUiKQpgYGAKCmBgYHtyfQpkZl9uYiAlPiUKICBiaW5kX3Jvd3Mob2JzU2NvcmVzICU+JSBmaWx0ZXIocGhhc2U9PSJwcmUiKSAlPiUgbXV0YXRlKHR5cGU9InByZWRpY3RlZCIpICU+JSBmaWx0ZXIoc2NhbGUhPSJkaXNlYXNlU2V2ZXJlIikpICU+JQogIHNwcmVhZChwaGFzZSwgTWVhbikgJT4lCiAgbXV0YXRlKGRpZmY9cG9zdC1wcmUpICU+JQogIGdyb3VwX2J5KHdvcmtlcklkLCBzY2FsZSwgdHlwZSkgJT4lCiAgc3VtbWFyaXplKGRpZmY9Zmlyc3QoZGlmZikpICU+JQogIGdyb3VwX2J5KHdvcmtlcklkKSAlPiUKICBzcHJlYWQodHlwZSwgZGlmZikgJT4lCiAgZ2dwbG90KGFlcyh4PXByZWRpY3RlZCwgeT1vYnNlcnZlZCkpICsKICBnZW9tX3BvaW50KHNoYXBlPTEsIHNpemU9LjUsIGNvbG9yPSJkYXJrdHVycXVvaXNlIikgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArCiAgZmFjZXRfd3JhcCh+c2NhbGUpCmBgYAoKVGhvdWdoIGFnYWluLCB2ZXJ5IHBvb3IgaW5kaXZpZHVhbC1sZXZlbCBwcmVkaWN0aW9ucy4KCk9mIGNvdXJzZSwgb3VyIGxlYXJuZWQgc3RydWN0dXJlIGFjY291bnRzIGZvciB0aGUgb3JpZ2luYWwgY29ycmVsYXRpb25hbCBkYXRhIGZhciAoaW5maW5pdGVseT8pIGJldHRlci4gQXMgcmV2ZWFsZWQgYnkgYSAkXERlbHRhIEFJQyQgaW4gdGhlIHRob3VzYW5kcy4KCmBgYHtyfQojIGNvbXBhcmluZyBtb2RlbHMgb24gdGhlIG9yaWdpbmFsIGRhdGEKIyBtYWRkZW5pbmdseSwgYm5sZWFybidzIEFJQyB2YWx1ZXMgYXJlIHJlc2NhbGVkIGJ5IC0yLCBzbyB0aGF0IGdyZWF0ZXIgdmFsdWVzIGFyZSBiZXR0ZXIhCgpuYl9zdHJ1Y3QgPC0gZGZfdG9fYm5sZWFybl9zdHJpbmcobmJfYXJjcykKbmJfc3RydWN0IDwtIG1vZGVsMm5ldHdvcmsobmJfc3RydWN0KQoKcHJpbnQocGFzdGUwKCJuYcOvdmUgc3RydWN0dXJlIEFJQyA9ICIsIHJvdW5kKEFJQyhuYl9zdHJ1Y3QsIGRfYm4pKSwyKSkKcHJpbnQocGFzdGUwKCJsZWFybmVkIHN0cnVjdHVyZSBBSUMgPSAiLCByb3VuZChBSUMobmV0LnN0cnVjdCwgZF9ibiksMikpKQpgYGAKCgoKIyBQcmVsaW1pbmFyeSBjb25jbHVzaW9ucwoKT24gc29tZSByZWZsZWN0aW9uLCB0aGVzZSByZXN1bHRzIHNob3VkbG4ndCBoYXZlIGJlZW4gc28gc2hvY2tpbmcuIFNpbmNlIHRoZSBzdHJ1Y3R1cmUgbGVhcm5pbmcgYWxnb3JpdGhtIGlzIHdvcmtpbmcgdG8gZmluZCBhIGdyYXBoIHRoYXQgcHJlc2VydmVzIHRoZSBjb3JyZWxhdGlvbnMgYW1vbmcgdmFyaWFibGVzLCBpdCdzIG5vdCBzbyBzdXJwcmlzaW5nIHRoYXQgY29uZGl0aW9uaW5nIG9uIGRpc2Vhc2Ugc2V2ZXJpdHkgaW4gdGhlIGdyYXBoIHByb2R1Y2VzIHJvdWdobHkgdGhlIHNhbWUgcHJlZGljdGlvbnMgYXMgYSBzZXQgb2YgcmVncmVzc2lvbiBtb2RlbHMgcHJlZGljdGluZyBhbGwgb3RoZXIgbm9kZSBmcm9tIGRpc2Vhc2Ugc2V2ZXJpdHkgKG9yIGVxdWl2YWxlbnRseSwgdGhlICJuYcOvdmUiIG5ldHdvcmsgSSB1c2VkIGhlcmUpLiBIb3dldmVyLCB0aGUgZmFjdCB0aGF0IHRob3NlIHByZWRpY3Rpb25zIG1hcCByZWFzb25hYmx5IHdlbGwgb250byB3aGF0IHdlIG9ic2VydmUgaXMgc3RpbGwgaW1wb3J0YW50IQoKX19XaGF0J3MgYmV0dGVyIGFib3V0IHRoZSBuZXR3b3JrIHN0cnVjdHVyZSBtb2RlbHMgY29tcGFyZWQgd2l0aCBuYcOvdmUgb3IgdW5pdmFyaWF0ZSBtb2RlbHM/X18KCjEuIEZpdCBib3RoIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIGFsbCBzY2FsZXMgYW5kIHByZWRpY3QgY2hhbmdlIHNjb3JlcyBvbiBhbGwgc2NhbGVzCjIuIFByZWRpY3QgZWZmZWN0cyBvZiBlZHVjYXRpb25hbCBpbnRlcnZlbnRpb25zIG9uIGFueSBub2RlIG9yIG11bHRpcGxlIG5vZGVzLCBhbGwgaW4gb25lIG1vZGVsCjMuIEdpdmUgd2F5cyB0byBoZWxwIGRpYWdub3NlIHdoaWNoIG5vZGVzIHdlcmUgZGlyZWN0bHkgYWZmZWN0ZWQgYnkgaW50ZXJ2ZW50aW9ucwo0LiAoQXJndWFibHkpIGJldHRlciBhbGxvdyBpbnRlcnByZXRhdGlvbiBvZiBvdmVyYWxsIHN0cnVjdHVyZSBvZiBiZWxpZWYgc3lzdGVtLCBiZXR0ZXIgcHJvdmlkZSBpbnNpZ2h0cywgZXRjCjUuIFNlcnZlIGFzIGEgY29nbml0aXZlIG1vZGVsIG9mIHRoZSBiZWxpZWYgc3lzdGVtIGluIGltcG9ydGFudCB3YXlzCgpJZiB3ZSBoYXZlIHRocmVlIG1vZGVscywgb25lIHRoYXQgbGV0cyB1cyBkbyBwcmVkaWN0aW9uIGluIG9uZSBkb21haW4sIGFub3RoZXIgdGhhdCBsZXRzIHVzIHRvIGRvIHByZWRpY3Rpb24gaW4gYW5vdGhlciBkb21haW4sIGFuZCBvbmUgdGhhdCBkb2VzIGJvdGggLS0gd2Ugc2hvdWxkIHByZWZlciB0aGUgb25lIHRoYXQgZG9lcyBib3RoLiBMaWtld2lzZSwgaWYgd2UgaGF2ZSB0aHJlZSBtb2RlbHMsIG9uZSB0aGF0IGxldHMgdXMgZG8gcHJlZGljdGlvbiwgb25lIHRoYXQgcHJvdmlkZXMgYW4gaW50ZWxsaWdpYmxlIGNvZ25pdGl2ZSB0aGVvcnksIGFuZCBvbmUgdGhhdCBkb2VzIGJvdGgtLXdlIHNob3VsZCBwcmVmZXIgdGhlIG9uZSB0aGF0IGRvZXMgYm90aC4gU28gaXQgd291bGQgaGF2ZSBiZWVuIChvciB3b3VsZCBiZSkgYSBsb3QgbW9yZSBleGNpdGluZyBpZiB0aGUgdGhlb3J5IG1vZGVscyBjb3VsZCBvdXRwZXJmb3JtIHRoZSBuYcOvdmUgbW9kZWxzIG9uIGJvdGggdGFza3MsIGJ1dCBpdCdzIHN0aWxsIGludGVyZXN0aW5nL2Nvb2wgaWYgdGhleSBkbyBhdCBsZWFzdCBhcyB3ZWxsIG9uIG11bHRpcGxlIHRhc2tzIGFzIHRoZSBvdGhlciBtb2RlbHMgZWFjaCBkbyBvbiB0aGVpciBvbmUgdGFzay4gCgpUaGF0IGZpbmFsIHBvaW50IGlzIGltcG9ydGFudCB0b28uIFRoZSAocHJlc3VtZWQpIGZhY3QgdGhhdCB0aGUgbW9kZWwgd2lsbCBkbyBiZXR0ZXIgcHJlZGljdGlvbiB0cmVhdGVkIGFzIGEgY29nbml0aXZlIG1vZGVsIHRoYW4gYXMgYSBjYXVzYWwgbW9kZWwgaXMgdmVyeSBpbmZvcm1hdGl2ZS4gSW4gYSBzZW5zZSwgaXQncyBhY3R1YWxseSBzdXBwb3J0ZWQgYnkgdGhlIG5hw692ZSBtb2RlbHMgdG9vLiBBIG5hw692ZSBtb2RlbCB3aGVyZSBkaXNlYXNlIHNldmVyaXR5IHByZWRpY3RzIGFsbCBiZWxpZWZzIGlzIGEgdmVyeSBwb29yIG1vZGVsIG9mIHRoZSBvdmVyYWxsIHN5c3RlbS4gQnV0LCBpdCBpcyBhIGRlY2VudCBtb2RlbCBvZiBob3cgdGhlIGJlbGllZnMgY2hhbmdlLiBUaGlzIHdvdWxkIGJlIF92ZXJ5IHVubGlrZWx5XyBpZiB3aGF0IHdlIHdlcmUgbW9kZWxpbmcgd2FzIGEgc2ltcGxlIGNhdXNhbCBzeXN0ZW0uIAoKVGhpcyBhbHNvIHN1Z2dlc3RzIGEgbW9yZSBnZW5lcmFsIGxlc3NvbjogSWYgYmVsaWVmcyBhcmUgc3VmZmljaWVudGx5IGludGVyY29ubmVjdGVkIGFuZCB0aGVyZSBhcmUgZmV3IHYtc3RydWN0dXJlcywgdGhlbiB0aGUgZGlyZWN0aW9ucyBvZiBlYWNoIGVkZ2UgbWF5IG1hdHRlciB2ZXJ5IGxpdHRsZSBpbiB0ZXJtcyBvZiBwcmVkaWN0aW9uLiBPZiBjb3Vyc2UsIHRoaXMgYWxzbyBtZWFucyB0aGF0IHNldHRpbmcgdGhvc2UgZWRnZSBkaXJlY3Rpb25zIChpZiB3ZSBjYXJlIHRvIGRvIHNvKSwgaXMgZ29pbmcgdG8gYmUgZGlmZmljdWx0LiBJdCBtaWdodCBhbHNvIG1lYW4gaXQncyBub3QgdGhlIHJpZ2h0IHdheSBvZiBjb25jaWV2aW5nIG9mIHRoZSByZWxhdGlvbnNoaXBzIGFtb25nIGJlbGllZnMuIAoKIyBHb2luZyBmb3J3YXJkCgpJbiB0aGUgbmV4dCBtb250aCBvciB0d28sIEkgdGhpbmsgd2Ugc2hvdWxkIHRyeSB0byBhZGRyZXNzIGEgZmV3IHF1ZXN0aW9ucyBiZWZvcmUgbW92aW5nIHRvIHB1Ymxpc2ggLi4uCgoxLiBDYW4gd2UgdXNlIG1vcmUgc29waGlzdGljYXRlZCB0ZWNobmlxdWVzIHRvIGxlYXJuIGEgYmV0dGVyIGluaXRpYWwgbW9kZWwgdGhhdCBvdXRwZXJmb3JtcyBuYcOvdmUgbW9kZWxzPwoyLiBDYW4gd2UgdXNlIHRoaXMgaW50ZXJ2ZW50aW9uIGRhdGEgdG8gbGVhcm4gYSBiZXR0ZXIgbW9kZWwgdGhhdCB3aWxsIGJlZ2luIHRvIG91dHBlcmZvcm0gbmHDr3ZlIG1vZGVscz8KMy4gSG93IGZhciBjYW4gd2UgcHVzaCAibmHDr3ZlIiBtb2RlbHMgaW4gdGVybXMgb2YgZG9pbmcgcHJlZGljdGlvbnM/